#include "epoll_loop.hpp"
#include "lock_guard.hpp"
#include "mutex_lock.hpp"
#include <iostream>
#include <sys/eventfd.h>

using std::cout;
using std::endl;

namespace rocket    
{
epoll_loop::epoll_loop(acceptor *accept)
:_acceptor(accept)
,_tcp_link_list()
,_epoll(epoll_create1(0))
,_eventfd(eventfd(0,0))
,_events(1024)
,_lock()
{
    
}
epoll_loop::~epoll_loop()
{

}
void epoll_loop::loop()
{
    _running_status=true;

    add_epoll_read_event(_acceptor->get_fd());
    add_epoll_read_event(_eventfd);

    while(_running_status==true)
    {
        int count=epoll_wait(_epoll, _events.data(), _events.capacity(), -1);
        if(count<0)
        {
            perror("epoll_wait");
        }
        for(int i=0;i<count;++i)
        {
            cout<<"count="<<count<<" i="<<i<<" fd="<<_events[i].data.fd<<endl;
            if(_events[i].data.fd==_acceptor->get_fd())
            {
                int new_link_fd=_acceptor->accept();
                add_epoll_read_event(new_link_fd);
                shared_ptr<tcp_link>the_new_link(new tcp_link(new_link_fd,this));
                the_new_link->set_callback(_new, _old, _close);
                _tcp_link_list[new_link_fd]=the_new_link;  
                the_new_link->new_link();
            }
            else if(_events.at(i).data.fd==_eventfd)
            {
//                cout<<"loop deal_send"<<endl;
                deal_send();
            }
            else if(_tcp_link_list.count(_events[i].data.fd)!=0)
            {
                char buff[10]={0};
                if(_tcp_link_list[_events[i].data.fd]->link_status()==true)
                {
                    _tcp_link_list[_events[i].data.fd]->old_link();
                }
                else
                {
                    _tcp_link_list[_events[i].data.fd]->close_link();

                    delete_epoll_read_event(_events[i].data.fd);
                
                }
            }

        }
    }
}

void epoll_loop::turn_off_loop()
{
    _running_status=false;
}

void epoll_loop::set_callback(function<void (shared_ptr<tcp_link>)> callback_new,
                             function<void (shared_ptr<tcp_link>)> callback_old, 
                             function<void (shared_ptr<tcp_link>)> callback_close)
{
    _new=callback_new;
    _old=callback_old;
    _close=callback_close;
}

void epoll_loop::notify(function<void ()>send_task )
{
    {
        lock_guard guard(_lock.get_mutex_lock_pointer());
        _send_list.push_back(std::move(send_task));
    }
    uint64_t one=1;
    write(_eventfd, &one, sizeof(one));

}

void epoll_loop::deal_send()
{
    uint64_t number=0;
    int ret=read(_eventfd, &number, sizeof(number));
    if(ret!=8)
    {
        perror("read");
    }
    cout<<"deal_send ret="<<ret<<endl;
    vector<function<void()>>temp;
    temp.swap(_send_list);
    for(auto ele:temp)
    {
        send_task_callback(std::move(ele));
    }
}

void epoll_loop::new_link(shared_ptr<tcp_link> new_one)
{
    _new(new_one);
}

void epoll_loop::old_link(shared_ptr<tcp_link> old_one)
{
    _old(old_one);
}


void epoll_loop::close_link(shared_ptr<tcp_link> close_one)
{
    _close(close_one);
}


void epoll_loop::add_epoll_read_event(int fd)
{
    epoll_event event;
    memset(&event, 0, sizeof(event));
    event.events=EPOLLIN;
    event.data.fd=fd;
    epoll_ctl(_epoll, EPOLL_CTL_ADD, fd, &event);

}

void epoll_loop::delete_epoll_read_event(int fd)
{
    epoll_event event;
    memset(&event, 0, sizeof(event));
    event.data.fd=fd;
    event.events=EPOLLIN;
    epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, &event);
    close(fd);
    _tcp_link_list.erase(fd);
               
}

void epoll_loop::send_task_callback(function<void()>send_task)
{
//    cout<<"send_task_callback before lock"<<endl;
    lock_guard guard(_lock.get_mutex_lock_pointer());
//    std::unique_lock<std::mutex>lock(_lock);
//    cout<<"send_task_callback in lock"<<endl;

    send_task();
}    


}
